#include "Check.h"
#include "simdjson.h"

void records_join(std::vector<std::string> &records, std::string &records_string)
{
    std::ostringstream oss;
    for (const auto &line : records)
    {
        oss << line << "\n";
    }
    records_string = oss.str();
}

// 特殊键映射表
const std::unordered_map<std::string, std::string> SPECIAL_KEYS = {
    {"\u001bOD", "[LEFT]"},    // 左箭头
    {"\u001bOC", "[RIGHT]"},   // 右箭头
    {"\u001bOA", "[UP]"},      // 上箭头
    {"\u001bOB", "[DOWN]"},    // 下箭头
    {"\r", "[ENTER]"},         // 回车
    {"\u007f", "[BACKSPACE]"}, // 退格键
    {"\u001b", "[ESC]"}};      // esc键

void process_cast_file(std::vector<std::string> &records, const std::filesystem::path &cast_file, std::vector<std::string> &copy_str)
{
    std::ifstream file(cast_file);
    if (!file.is_open())
    {
        std::cerr << "Error: Could not open file '" << cast_file << "'" << std::endl;
        return;
    }
    std::string head = "\u001b";
    std::string prefix = "\u001b[200~";
    std::string suffix = "\u001b[201~";

    // 创建 simdjson 解析器
    simdjson::dom::parser parser;
    std::string line;
    std::string current_text;

    // 跳过第一行（通常是header）
    std::getline(file, line);

    while (std::getline(file, line))
    {
        // 跳过空行
        if (line.empty())
            continue;

        // 确保字符串以null结尾且正确初始化
        line.shrink_to_fit();

        try
        {
            // 解析单行JSON
            simdjson::dom::element event;
            auto error = parser.parse(line).get(event);
            if (error)
            {
                std::cerr << "Error parsing line: " << line << "\nError: " << simdjson::error_message(error) << std::endl;
                continue;
            }

            // 检查是否为数组 [time, type, data]
            simdjson::dom::array event_array;
            if (!event.is_array() || event.get(event_array))
            {
                continue;
            }

            // 检查数组长度是否为3
            if (event_array.size() != 3)
            {
                continue;
            }

            // 检查事件类型是否为输入 ('i')
            std::string_view event_type;
            if (event_array.at(1).get(event_type))
            {
                continue;
            }

            if (event_type != "i")
            {
                continue; // 只处理输入事件
            }

            // 获取事件数据
            std::string_view event_data;
            if (event_array.at(2).get(event_data))
            {
                continue;
            }

            auto str = std::string(event_data);

            // 检查是否是特殊键
            auto it = SPECIAL_KEYS.find(str);
            if (it != SPECIAL_KEYS.end())
            {
                // 如果有累积的普通字符，先添加
                if (!current_text.empty())
                {
                    records.push_back(current_text);
                    current_text.clear();
                }
                // 添加特殊键标记
                records.push_back(it->second);
            }
            // 带有标识符的复制文本
            else if (str.find("rgb:cccc/cccc/cccc") != std::string::npos)
            {
                continue;
            }
            else if (str.size() >= prefix.size() && str.compare(0, prefix.size(), prefix) == 0)
            {
                // 去除前缀和后缀
                str = str.substr(prefix.size(), str.size() - prefix.size() - suffix.size());
                copy_str.push_back(str);
                current_text += str;
            }
            // 处理疑似非键盘输入
            else if (str.compare(0, head.size(), head) != 0 && str.size() > 2)
            {
                copy_str.push_back(str);
                current_text += str;
            }
            else
            {
                // 不是特殊键，累积到当前文本
                current_text += str;
            }
        }
        catch (const std::exception &e)
        {
            std::cerr << "Exception while processing line: " << e.what() << std::endl;
            continue;
        }
    }

    // 添加最后累积的文本
    if (!current_text.empty())
    {
        records.push_back(current_text);
    }
}

std::vector<std::string> process_cast_file_init(const std::filesystem::path &cast_file)
{
    std::vector<std::string> records;
    std::ifstream file(cast_file);
    if (!file.is_open())
    {
        std::cerr << "Error: Could not open file '" << cast_file << "'" << std::endl;
    }

    std::string prefix = "\u001b[200~";
    std::string suffix = "\u001b[201~";

    // 创建 simdjson 解析器
    simdjson::dom::parser parser;
    std::string line;
    std::string current_text;

    // 跳过第一行（通常是header）
    std::getline(file, line);

    while (std::getline(file, line))
    {
        // 跳过空行
        if (line.empty())
            continue;

        // 确保字符串以null结尾且正确初始化
        line.shrink_to_fit();

        try
        {
            // 解析单行JSON
            simdjson::dom::element event;
            auto error = parser.parse(line).get(event);
            if (error)
            {
                std::cerr << "Error parsing line: " << line << "\nError: " << simdjson::error_message(error) << std::endl;
                continue;
            }

            // 检查是否为数组 [time, type, data]
            simdjson::dom::array event_array;
            if (!event.is_array() || event.get(event_array))
            {
                continue;
            }

            // 检查数组长度是否为3
            if (event_array.size() != 3)
            {
                continue;
            }

            // 检查事件类型是否为输入 ('i')
            std::string_view event_type;
            if (event_array.at(1).get(event_type))
            {
                continue;
            }

            if (event_type != "i")
            {
                continue; // 只处理输入事件
            }

            // 获取事件数据
            std::string_view event_data;
            if (event_array.at(2).get(event_data))
            {
                continue;
            }

            auto str = std::string(event_data);
            // 检查是否是特殊键
            auto it = SPECIAL_KEYS.find(str);
            if (it != SPECIAL_KEYS.end())
            {
                // 如果有累积的普通字符，先添加
                if (!current_text.empty())
                {
                    records.push_back(current_text);
                    current_text.clear();
                }
                // 添加特殊键标记
                records.push_back(it->second);
            }
            // 带有标识符的复制文本
            else if (str.find("rgb:cccc/cccc/cccc") != std::string::npos)
            {
                continue;
            }
            else
            {
                // 不是特殊键，累积到当前文本
                current_text += str;
            }
        }
        catch (const std::exception &e)
        {
            std::cerr << "Exception while processing line: " << e.what() << std::endl;
            continue;
        }
    }

    // 添加最后累积的文本
    if (!current_text.empty())
    {
        records.push_back(current_text);
    }

    return records;
}

/**
 * @brief  check_similarity，用于检查给定字符串与目录中文件的相似度
 * @param  records_string 是要比较的字符串
 * @param  cast_lib_dir 是要扫描的目录路径
 */
std::vector<FileSimilarity> check_similarity(
    const std::string &records_string,
    const std::filesystem::path &cast_lib_dir)
{
    // 创建一个存储目标文件路径的向量
    std::vector<std::filesystem::path> target_files;

    // 递归遍历目录及其所有子目录中的条目
    for (const auto &entry : std::filesystem::recursive_directory_iterator(cast_lib_dir))
    {
        // 检查当前条目是否是普通文件（非目录）
        if (entry.is_regular_file())
        {
            // 如果是文件，将其路径添加到目标文件列表中
            target_files.push_back(entry.path());
        }
    }

    // 检查目标文件列表是否为空
    if (target_files.empty())
    {
        // 如果目录中没有文件，输出错误信息并返回空向量
        std::cerr << "Error: No files in directory" << std::endl;
        return {};
    }

    // 创建一个 FileSimilarity 类型的向量，大小与目标文件数量相同
    // FileSimilarity 可能是一个结构体，包含文件路径和相似度分数
    std::vector<FileSimilarity> similar_files(target_files.size());

    // 创建一个互斥锁，用于保护多线程访问 similar_files 向量
    std::mutex similar_files_mutex;

    // 使用并行算法 for_each 处理每个目标文件
    std::for_each(std::execution::par,
                  target_files.begin(),
                  target_files.end(),
                  [&](const std::filesystem::path &file_path)
                  {
                      // 计算当前文件在向量中的索引
                      size_t index = &file_path - &target_files[0];

                      // 定义一个字符串变量来存储文件内容
                      std::string content;

                      // 使用代码块限制文件流的作用域
                      {
                          // 打开文件
                          std::ifstream file(file_path);
                          // 如果文件打开失败，直接返回
                          if (!file)
                              return;

                          // 将文件指针移动到文件末尾以获取文件大小
                          file.seekg(0, std::ios::end);
                          // 预留足够空间存储文件内容
                          content.reserve(file.tellg());
                          // 将文件指针移回文件开头
                          file.seekg(0, std::ios::beg);
                          // 读取整个文件内容到字符串中
                          content.assign(std::istreambuf_iterator<char>(file),
                                         std::istreambuf_iterator<char>{});
                      }

                      // 使用 rapidfuzz 库计算 records_string 和文件内容的相似度
                      double similarity = rapidfuzz::fuzz::ratio(records_string, content);

                      // 使用互斥锁保护对共享数据的访问
                      {
                          std::lock_guard<std::mutex> lock(similar_files_mutex);
                          // 将文件路径和相似度分数存储到结果向量中
                          similar_files[index] = {file_path, similarity};
                      }
                  });

    // 使用并行算法对结果向量进行排序
    // 这里假设 FileSimilarity 类型已定义了比较操作符
    std::sort(std::execution::par, similar_files.begin(), similar_files.end());

    // 返回包含所有文件相似度信息的有序向量
    return similar_files;
}